package com.ynding;

import java.applet.Applet;
import java.applet.AudioClip;
import java.awt.*;

/**
 * <p> 多功能时钟 </p>
 *
 * @author ynding
 * @version 2021/4/14
 **/

//代表下拉式编辑框，用来输入小时、分钟和秒
class SpinButton {
    int x, y, number, maxVal, runner;
    Font font1 = new Font("Dialog", Font.BOLD, 14);
    boolean up, down;
    long timeSet;

    //构造函数
    public SpinButton(int x, int y, int max) {
        this.x = x;
        this.y = y;
        maxVal = max;
    }

    //初始化
    public void init() {
        number = 0;
    }

    //画组件
    public void DrawControl(Graphics g) {
        g.setColor(Color.white);
        g.fillRect(x, y, 25, 18);
        g.setColor(Color.lightGray);
        g.fill3DRect(x + 25, y, 14, 9, !up);
        g.fill3DRect(x + 25, y + 9, 14, 9, !down);
        g.setColor(Color.black);
        UpTriangle(g, x + 28, y + 2, 8, 5);
        DownTriangle(g, x + 29, y + 16, 7, 4);
        g.setFont(font1);
        g.drawString("" + number, x + 5, y + 14);
    }

    //画向上的三角形
    public void UpTriangle(Graphics g, int x, int y, int w, int h) {
        int a[] = {x, (x + w / 2), x + w};
        int b[] = {y + h, y, y + h};
        g.fillPolygon(a, b, 3);
    }

    //画向下的三角形
    public void DownTriangle(Graphics g, int x, int y, int w, int h) {
        int a[] = {x, (x + w / 2), x + w};
        int b[] = {y - h, y, y - h};
        g.fillPolygon(a, b, 3);
    }

    //处理mouseDown事件
    public boolean mouseDown(int xx, int yy) {
        if (xx > x + 25 && xx < x + 40 && yy > y && yy < y + 9) {
            up = true;
            return true;
        }
        if (xx > x + 25 && xx < x + 40 && yy > y + 9 && yy < y + 18) {
            down = true;
            return true;
        }
        return false;
    }

    //处理mouseUp事件
    public void mouseUp() {
        up = down = false;
    }

    public int GetNumber() {
        return number;
    }

    //当用户按住上下键不松开时，增加或减小值
    public void Update() {
        runner++;
        if (runner % 2 == 0) {
            if (up) {
                if (number < maxVal) number++;
                else number = 0;
            }
            if (down) {
                if (number > 0) number--;
                else number = maxVal;
            }
        }
    }
}

//代表是否播放声音、倒计时还是正计时的CheckBox类
class CheckBox {
    int x, y;
    Font font1 = new Font("Helvetica", Font.BOLD, 9);
    boolean checked, clicked;
    String string, message;
    int stringWidth;

    //构造函数
    public CheckBox(int x, int y, String str, boolean checked) {
        this.x = x;
        this.y = y;
        this.string = str;
        this.checked = checked;
    }

    //初始化
    public void init() {

    }

    //画组件
    public void DrawControl(Graphics g) {
        g.setFont(font1);
        FontMetrics fm = g.getFontMetrics(font1);
        stringWidth = fm.stringWidth(string);
        g.setColor(Color.white);
        g.fillOval(x, y, 13, 13);
        g.fillRect(x + 20, y, stringWidth + 9, 13);
        g.setColor(Color.black);
        if (checked)
            g.fillOval(x + 4, y + 4, 5, 5);
        g.drawString(string, x + 25, y + 10);
    }

    //处理mouseDown事件
    public boolean mouseDown(int xx, int yy) {
        if (xx > x && xx < x + stringWidth + 30 && yy > y && yy < y + 13) {
            clicked = true;
            return true;
        }
        return false;
    }

    //处理mouseUp事件
    public void mouseUp() {
        clicked = false;
    }
}

/**
 * 定义Timer类
 *
 * @author Administrator
 */
public class Timer extends Applet implements Runnable {
    Thread Clock_animation;//定义线程
    private Image Buffer;
    private Graphics gBuffer;
    long currTime, startTime, diffTime, pauseValue, timeSet;
    int hours, minutes, seconds, runner, soundRunner;
    boolean pressedStart, pressedStop, pressedReset, pressedEnlarge, countDown;
    boolean paused, enlarged, running, playSound, input, blink, framed;
    boolean soundDelay;
    //用来完成旋转的变量
    int ox = 0;
    int oy = 0;
    double radians = 0.0;
    double cos = 1.0;
    double sin = 0.0;
    AudioClip alarmSound;
    Font font1 = new Font("Dialog", Font.PLAIN, 14);
    Font font2 = new Font("Dialog", Font.BOLD, 11);
    Font font3 = new Font("Helvetica", Font.BOLD, 25);
    Font font4 = new Font("Helvetica", Font.BOLD, 9);
    Font font5 = new Font("Helvetica", Font.BOLD, 16);
    Color color1 = new Color(25, 55, 135);
    Color color2 = new Color(225, 225, 225);
    Color bgColor = new Color(0, 0, 0);
    SpinButton sb1, sb2, sb3;
    CheckBox cb1, cb2, cb3;
    String message;

    //初始化
    @Override
    public void init() {
        Buffer = createImage(size().width, size().height);
        gBuffer = Buffer.getGraphics();
        //载入警报声
        try {
            alarmSound = getAudioClip(getCodeBase(), "alarm.au");
        } catch (Exception e) {
        }
        sb1 = new SpinButton(110, 280, 99);
        sb2 = new SpinButton(110, 300, 59);
        sb3 = new SpinButton(110, 320, 59);
        cb1 = new CheckBox(52, 124, "Count Down", false);
        cb2 = new CheckBox(52, 144, "Count Up", true);
        cb3 = new CheckBox(10, 244, "Play Sound", true);
        playSound = true;
        currTime = startTime = diffTime = pauseValue = timeSet = 0;
        message = getParameter("timer_name");
        String r, g, b;
        int rt, gr, bl;
        //设置颜色参数
        String clockColorStr = getParameter("clock_color");
        r = clockColorStr.substring(0, 2);
        g = clockColorStr.substring(2, 4);
        b = clockColorStr.substring(4);
        rt = Integer.parseInt(r, 16);
        gr = Integer.parseInt(g, 16);
        bl = Integer.parseInt(b, 16);
        color1 = (new Color(rt, gr, bl));
        String bgColorStr = getParameter("bg_color");
        r = bgColorStr.substring(0, 2);
        g = bgColorStr.substring(2, 4);
        b = bgColorStr.substring(4);
        rt = Integer.parseInt(r, 16);
        gr = Integer.parseInt(g, 16);
        bl = Integer.parseInt(b, 16);
        bgColor = (new Color(rt, gr, bl));
    }

    //开始线程
    @Override
    public void start() {
        if (Clock_animation == null) {
            Clock_animation = new Thread(this);
            Clock_animation.start();
        }
    }

    //停止线程
    @Override
    public void stop() {
        if (Clock_animation != null) {
            Clock_animation.stop();
            Clock_animation = null;
        }
    }

    //运行
    public void run() {
        while (true) {
            try {
                Clock_animation.sleep(100);
            } catch (Exception e) {
            }

            runner++;
            if (runner > 5) {
                runner = 0;
            }

            if (soundDelay) {
                soundRunner++;

                if (soundRunner > 50) {
                    alarmSound.stop();
                    soundRunner = 0;
                    soundDelay = false;
                }
            }
            if (runner < 3) {
                blink = true;
            } else {
                blink = false;
            }
            sb1.Update();
            sb2.Update();
            sb3.Update();
            DrawBackground();
            DrawTextArea();
            DrawGauge();
            DrawClock();
            DrawCircle();
            if (!paused && running) {
                CalculateTime();
            }
            ObserveTimer();
            repaint();
        }
    }

    //播放警报声
    void ObserveTimer() {
        if (countDown && running)
            if (hours == 0 && minutes == 0 && seconds == 0) {
                if (playSound)
                    alarmSound.loop();

                soundDelay = true;
                running = false;
            }
    }

    //画背景
    void DrawBackground() {
        gBuffer.setColor(bgColor);
        gBuffer.fillRect(0, 0, 190, 350);
        gBuffer.setColor(color1);
        if (enlarged)
            gBuffer.fillRoundRect(0, 0, 190, 350, 32, 32);
        else
            gBuffer.fillRoundRect(0, 0, 190, 270, 32, 32);

        gBuffer.setColor(Color.lightGray);

        gBuffer.fill3DRect(22, 90, 46, 20, !pressedStart);

        gBuffer.fill3DRect(72, 90, 46, 20, !pressedStop);

        gBuffer.fill3DRect(122, 90, 46, 20, !pressedReset);
        gBuffer.setFont(font2);
        gBuffer.setColor(Color.black);
        gBuffer.drawString("START", 24, 104);
        gBuffer.drawString("STOP", 78, 104);
        gBuffer.drawString("RESET", 125, 104);
        gBuffer.setColor(color2);
        gBuffer.fill3DRect(100, 242, 19, 18, !pressedEnlarge);
        gBuffer.setColor(Color.black);
        DrawTriangle(104, 256, 10, 8);
        gBuffer.setFont(font2);
        gBuffer.setColor(Color.white);
        gBuffer.drawString("Set Timer", 125, 255);
        if (enlarged) {
            gBuffer.drawString("Hours", 30, 295);
            gBuffer.drawString("Minutes", 30, 315);
            gBuffer.drawString("Seconds", 30, 335);
            sb1.DrawControl(gBuffer);
            sb2.DrawControl(gBuffer);
            sb3.DrawControl(gBuffer);
        } else {
            gBuffer.setFont(font4);
            gBuffer.setColor(Color.black);
            gBuffer.drawString("?2003 by Ali", 2, 322);

            gBuffer.setColor(Color.white);
            gBuffer.drawString("?2003 by Ali", 0, 320);
        }
        cb1.DrawControl(gBuffer);
        cb2.DrawControl(gBuffer);
        cb3.DrawControl(gBuffer);
    }

    //画时钟
    void DrawClock() {
        if (soundRunner > 0 && blink)
            gBuffer.setColor(Color.red);
        else
            gBuffer.setColor(Color.white);

        gBuffer.fillRoundRect(38, 45, 112, 30, 15, 15);

        gBuffer.setFont(font3);

        if (soundRunner > 0 && blink)
            gBuffer.setColor(Color.white);
        else
            gBuffer.setColor(Color.black);
        String s1, s2, s3;
        if (hours < 10) s1 = "0";
        else s1 = "";
        if (minutes < 10) s2 = "0";
        else s2 = "";
        if (seconds < 10) s3 = "0";
        else s3 = "";
        String output = s1 + hours + ":" + s2 + minutes + ":" + s3 + seconds;
        if (output.length() <= 8)
            gBuffer.drawString(output, 45, 69);
        else
            gBuffer.drawString("00:00:00", 45, 69);
    }

    public void update(Graphics g) {
        paint(g);
    }

    //paint()方法
    public void paint(Graphics g) {
        g.drawImage(Buffer, 0, 0, this);
    }

    //鼠标是否移动
    public boolean mouseMove(Event evt, int x, int y) {
        if (x > 20 && x < 170 && y > 200 && y < 220)
            framed = true;
        else
            framed = false;
        return true;
    }

    //鼠标是否按下
    public boolean mouseDown(Event evt, int x, int y) {
        sb1.mouseDown(x, y);
        sb2.mouseDown(x, y);
        sb3.mouseDown(x, y);
        cb1.mouseDown(x, y);
        cb2.mouseDown(x, y);
        cb3.mouseDown(x, y);
        if (cb1.clicked) {
            ResetTimer();
            cb1.checked = true;
            cb2.checked = false;
            countDown = true;
            if (!enlarged) enlarged = true;
            pressedReset = true;
        } else if (cb2.clicked) {
            ResetTimer();
            cb2.checked = true;
            cb1.checked = false;
            countDown = false;
            pressedReset = true;
        }
        if (cb3.clicked) {
            cb3.checked ^= true;
            playSound ^= true;
        }
        if (x > 22 && x < 68 && y > 90 && y < 110) {
            pressedStart = true;
            StartTimer();
        }
        if (x > 72 && x < 118 && y > 90 && y < 110) {
            pressedStop = true;
            StopTimer();
        }
        if (x > 122 && x < 168 && y > 90 && y < 110) {
            pressedReset = true;
            ResetTimer();
        }
        if (x > 100 && x < 120 && y > 242 && y < 262) {
            enlarged ^= true;
            pressedEnlarge = true;
        }
        if (x > 20 && x < 170 && y > 200 && y < 220) {
            input = true;
            message = "";
        } else input = false;
        if (soundDelay) {
            alarmSound.stop();
            soundRunner = 0;
            soundDelay = false;
        }
        repaint();
        return true;
    }

    //鼠标键是否被抬起
    public boolean mouseUp(Event evt, int x, int y) {
        pressedStart = pressedStop = pressedReset = pressedEnlarge = false;
        sb1.mouseUp();
        sb2.mouseUp();
        sb3.mouseUp();
        cb1.mouseUp();
        cb2.mouseUp();
        cb3.mouseUp();
        repaint();
        return true;
    }

    //开始计时
    void StartTimer() {
        long h = sb1.GetNumber();
        long m = sb2.GetNumber();
        long s = sb3.GetNumber();
        timeSet = (h * 3600 + m * 60 + s) * 1000;
        if (!running || paused) {
            if (!(timeSet == 0 && countDown)) {
                paused = false;
                running = true;

                startTime = System.currentTimeMillis();
            }
        }
    }

    //停止计时
    void StopTimer() {
        if (running) {
            if (!paused) {
                if (!countDown)
                    pauseValue = diffTime;
                else
                    pauseValue = (currTime - startTime) / 1000 + pauseValue;
            }
            paused = true;
        }
    }

    //重新设置计时器
    void ResetTimer() {
        running = false;
        pauseValue = diffTime = 0;
        startTime = System.currentTimeMillis();
        if (countDown) {
            long h = sb1.GetNumber();
            long m = sb2.GetNumber();
            long s = sb3.GetNumber();
            timeSet = (h * 3600 + m * 60 + s) * 1000;
            hours = (int) h;
            minutes = (int) m;
            seconds = (int) s;
        } else
            hours = minutes = seconds = 0;
    }

    //计算时间
    void CalculateTime() {
        currTime = System.currentTimeMillis();
        if (!countDown)
            diffTime = (currTime - startTime) / 1000 + pauseValue;
        else
            diffTime = ((timeSet - (currTime - startTime)) / 1000) - pauseValue;
        hours = (int) (diffTime - diffTime % 3600) / 3600;
        minutes = (int) ((diffTime - diffTime % 60) / 60) % 60;
        seconds = (int) diffTime % 60;
    }

    //画三角形
    void DrawTriangle(int x, int y, int w, int h) {
        int a[] = {x, (x + w / 2), x + w};
        int b[] = {y - h, y, y - h};
        gBuffer.fillPolygon(a, b, 3);
    }

    //画中心圆圈
    void DrawCenteredArc(int cx, int cy, int r, int beginArc, int arc) {
        int x = cx - r;
        int y = cy - r;
        gBuffer.drawArc(x - 87, y - 87, r * 2, r * 2, beginArc, arc);
    }

    //画圈
    void DrawCircle() {
        gBuffer.setColor(Color.red);
        gBuffer.drawOval(7, 12, 174, 174);
        gBuffer.setColor(new Color(0, 210, 120));
        int arc;
        int beginArc;
        int unit = minutes;
        if (countDown) {
            beginArc = unit * 6 + 90;
            arc = -unit * 6;
            if (hours > 0) arc = 360;
            else
                SetAngle(360 - unit * 6);
        } else {
            beginArc = 90;
            arc = -unit * 6;
            SetAngle(unit * 6);
        }
        for (int i = 0; i < 3; i++) {
            DrawCenteredArc(182, 186, 86 + i, beginArc, arc);
        }
        int centerX = 94;
        int centerY = 99;
        int radius = 87;
        ox = centerX;
        oy = centerY;
        int x[] = new int[3];
        int y[] = new int[3];
        x[0] = -7;
        x[1] = 7;
        x[2] = -7;
        y[0] = -radius - 7;
        y[1] = -radius;
        y[2] = -radius + 7;
        RotatePolygon(x, y, 3);
    }

    int rotate_x(int x, int y) {
        return ((int) (ox + x * cos - y * sin));
    }

    int rotate_y(int x, int y) {
        return ((int) (oy + y * cos + x * sin));
    }

    //设置角度
    void SetAngle(double a) {
        radians = (a * 2 * Math.PI) / 360;
        cos = Math.cos(radians);
        sin = Math.sin(radians);
    }

    //旋转多边形
    void RotatePolygon(int x[], int y[], int n) {
        int new_x[] = new int[3];
        int new_y[] = new int[3];
        for (int i = 0; i < n; i++) {
            new_x[i] = rotate_x(x[i], y[i]);
            new_y[i] = rotate_y(x[i], y[i]);
        }
        gBuffer.fillPolygon(new_x, new_y, n);
    }

    //判断键盘是否被按下
    public boolean keyDown(Event e, int key) {
        if (key == 10) input = false;
        else if (input)
            message = message + (char) key;
        return true;
    }

    //画文字编辑区域
    void DrawTextArea() {
        if (soundRunner > 0 && blink)
            gBuffer.setColor(Color.red);
        else
            gBuffer.setColor(Color.white);
        gBuffer.fillRect(20, 200, 150, 20);
        gBuffer.setColor(Color.orange);
        if (framed)
            gBuffer.drawRect(18, 198, 153, 23);
        if (soundRunner > 0 && blink)
            gBuffer.setColor(Color.white);
        else
            gBuffer.setColor(Color.black);
        gBuffer.setFont(font5);
        FontMetrics fm = gBuffer.getFontMetrics(font5);
        int stringWidth = fm.stringWidth(message);
        if (input && blink)
            gBuffer.drawString(message + "|", 25, 215);
        else if (input && !blink)
            gBuffer.drawString(message, 25, 215);
        else
            gBuffer.drawString(message, 95 - stringWidth / 2, 215);
    }

    //画凹槽
    void DrawGauge() {
        gBuffer.setColor(Color.green);
        gBuffer.fillRect(20, 222, 150, 10);
        int barL;
        float frac;
        if (diffTime > 0 && timeSet > 0) {
            frac = (float) ((timeSet - diffTime * 1000) / (float) timeSet);
            barL = (int) (frac * 150);
        } else barL = 0;
        if (paused)
            gBuffer.setColor(Color.blue);
        else
            gBuffer.setColor(Color.red);
        if (countDown) {
            gBuffer.fillRect(20, 222, barL, 10);
        } else if (running) {
            for (int i = -5; i < 150; i += 6)
                gBuffer.fillRect(20 + runner + i, 222, 3, 10);
            gBuffer.setColor(color1);
            gBuffer.fillRect(15, 222, 5, 10);
            gBuffer.fillRect(170, 222, 5, 10);
        }
    }
}
